home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / serial / setseria.10 / setseria / setserial-2.10 / setserial.c < prev   
C/C++ Source or Header  |  1994-05-20  |  11KB  |  437 lines

  1. /* setserial.c - get/set Linux serial port info - rick sladkey */
  2. /* modified to do work again and added setting fast serial speeds,
  3.    Michael K. Johnson, johnsonm@stolaf.edu */
  4. /*
  5.  * Very heavily modified --- almost rewritten from scratch --- to have
  6.  * a more flexible command structure.  Now able to set any of the
  7.  * serial-specific options using the TIOCSSERIAL ioctl().
  8.  *             Theodore Ts'o, tytso@mit.edu, 1/1/93
  9.  *
  10.  * Last modified: [tytso:19940520.0036EDT]
  11.  */
  12.  
  13. #include <stdio.h>
  14. #include <fcntl.h>
  15. #include <termios.h>
  16. #include <string.h>
  17. #include <errno.h>
  18.  
  19. #include <linux/fs.h>
  20. #include <linux/serial.h>
  21. #include <linux/tty.h>
  22.  
  23. #define VERSION_STR "2.10"
  24.  
  25. char *progname;
  26.  
  27. int    verbosity = 1;        /* 1 = normal, 0=boot-time, 2=everything */
  28. int    verbose_flag = 0;    /* print results after setting a port */
  29. int    quiet_flag = 0;
  30.  
  31. struct serial_type_struct {
  32.     int id;
  33.     char *name;
  34. } serial_type_tbl[] = {
  35.     PORT_UNKNOWN,    "unknown",
  36.     PORT_8250,    "8250",
  37.     PORT_16450,    "16450",
  38.     PORT_16550,    "16550",
  39.     PORT_16550A,    "16550A",
  40.     PORT_UNKNOWN,    "none",
  41.     -1,        NULL
  42. };
  43.  
  44. #define CMD_FLAG    1
  45. #define CMD_PORT    2
  46. #define CMD_IRQ        3
  47. #define CMD_DIVISOR    4
  48. #define CMD_TYPE    5
  49. #define CMD_BASE    6
  50. #define CMD_DELAY    7
  51. #define CMD_CONFIG    8
  52.  
  53. #define FLAG_CAN_INVERT    0x0001
  54. #define FLAG_NEED_ARG    0x0002
  55.  
  56. struct flag_type_table {
  57.     int    cmd;
  58.     char    *name;
  59.     int    bits;
  60.     int    mask;
  61.     int    level;
  62.     int    flags;
  63. } flag_type_tbl[] = {
  64.     CMD_FLAG,    "spd_normal",    0,        ASYNC_SPD_MASK,    2, 0,
  65.     CMD_FLAG,    "spd_hi",    ASYNC_SPD_HI,     ASYNC_SPD_MASK, 0, 0,
  66.     CMD_FLAG,    "spd_vhi",    ASYNC_SPD_VHI,    ASYNC_SPD_MASK,    0, 0,
  67.     CMD_FLAG,    "spd_cust",    ASYNC_SPD_CUST,    ASYNC_SPD_MASK,    0, 0,
  68.     
  69.     CMD_FLAG,     "SAK",         ASYNC_SAK,     ASYNC_SAK,     0, FLAG_CAN_INVERT,
  70.     CMD_FLAG,    "Fourport",    ASYNC_FOURPORT, ASYNC_FOURPORT,    0, FLAG_CAN_INVERT,
  71.     CMD_FLAG,    "hup_notify",    ASYNC_HUP_NOTIFY, ASYNC_HUP_NOTIFY, 0, FLAG_CAN_INVERT,
  72.     CMD_FLAG,    "skip_test",    ASYNC_SKIP_TEST,ASYNC_SKIP_TEST,2, FLAG_CAN_INVERT,
  73.     CMD_FLAG,    "auto_irq",    ASYNC_AUTO_IRQ,    ASYNC_AUTO_IRQ,    2, FLAG_CAN_INVERT,
  74. #ifdef ASYNC_SPLIT_TERMIOS
  75.     CMD_FLAG,    "split_termios", ASYNC_SPLIT_TERMIOS, ASYNC_SPLIT_TERMIOS, 2, FLAG_CAN_INVERT,
  76. #endif
  77.     CMD_FLAG,    "session_lockout", ASYNC_SESSION_LOCKOUT, ASYNC_SESSION_LOCKOUT, 2, FLAG_CAN_INVERT,
  78.     CMD_FLAG,    "pgrp_lockout", ASYNC_PGRP_LOCKOUT, ASYNC_PGRP_LOCKOUT, 2, FLAG_CAN_INVERT,
  79. #ifdef ASYNC_CALLOUT_NOHUP
  80.     CMD_FLAG,    "callout_nohup", ASYNC_CALLOUT_NOHUP, ASYNC_CALLOUT_NOHUP, 2, FLAG_CAN_INVERT,
  81. #endif    
  82.     
  83.     CMD_PORT,    "port",        0,        0,        0, FLAG_NEED_ARG,
  84.     CMD_IRQ,    "irq",        0,        0,        0, FLAG_NEED_ARG,
  85.     CMD_DIVISOR,    "divisor",    0,        0,        0, FLAG_NEED_ARG,
  86.     CMD_TYPE,    "uart",        0,        0,        0, FLAG_NEED_ARG,
  87.     CMD_BASE,    "base",        0,        0,        0, FLAG_NEED_ARG,
  88.     CMD_BASE,    "baud_base",    0,        0,        0, FLAG_NEED_ARG,
  89.     CMD_DELAY,    "close_delay",    0,        0,        0, FLAG_NEED_ARG,
  90.     CMD_CONFIG,    "autoconfig",    0,        0,        0, 0,
  91.     0,        0,        0,        0,        0, 0,
  92. };
  93.     
  94. char *serial_type(int id)
  95. {
  96.     int i;
  97.  
  98.     for (i = 0; serial_type_tbl[i].id != -1; i++)
  99.         if (id == serial_type_tbl[i].id)
  100.             return serial_type_tbl[i].name;
  101.     return "undefined";
  102. }
  103.  
  104. int uart_type(char *name)
  105. {
  106.     int i;
  107.  
  108.     for (i = 0; serial_type_tbl[i].id != -1; i++)
  109.         if (!strcasecmp(name, serial_type_tbl[i].name))
  110.             return serial_type_tbl[i].id;
  111.     return -1;
  112. }
  113.  
  114.  
  115. int atonum(char *s)
  116. {
  117.     int n;
  118.  
  119.     while (*s == ' ')
  120.         s++;
  121.     if (strncmp(s, "0x", 2) == 0 || strncmp(s, "0X", 2) == 0)
  122.         sscanf(s + 2, "%x", &n);
  123.     else if (s[0] == '0' && s[1])
  124.         sscanf(s + 1, "%o", &n);
  125.     else
  126.         sscanf(s, "%d", &n);
  127.     return n;
  128. }
  129.  
  130. void print_flags(struct serial_struct *serinfo,
  131.          char *prefix, char *postfix)
  132. {
  133.     struct    flag_type_table    *p;
  134.     int    flags;
  135.     int    first = 1;
  136.  
  137.     flags = serinfo->flags;
  138.     
  139.     for (p = flag_type_tbl; p->name; p++) {
  140.         if (p->cmd != CMD_FLAG)
  141.             continue;
  142.         if (verbosity < p->level)
  143.             continue;
  144.         if ((flags & p->mask) == p->bits) {
  145.             if (first) {
  146.                 printf("%s", prefix);
  147.                 first = 0;
  148.             } else
  149.                 printf(" ");
  150.             printf("%s", p->name);
  151.         }
  152.     }
  153.     
  154.     if (!first)
  155.         printf("%s", postfix);
  156. }
  157.  
  158. void get_serial(char *device)
  159. {
  160.     struct serial_struct serinfo;
  161.     int    fd;
  162.  
  163.     if ((fd = open(device, O_RDWR|O_NONBLOCK)) < 0) {
  164.         perror(device);
  165.         return;
  166.     }
  167.     if (ioctl(fd, TIOCGSERIAL, &serinfo) < 0) {
  168.         perror("Cannot get serial info");
  169.         close(fd);
  170.         return;
  171.     }
  172.     if (serinfo.irq == 9)
  173.         serinfo.irq = 2;    /* People understand 2 better than 9 */
  174.     if (verbosity==2) {
  175.         printf("%s, Line %d, UART: %s, Port: 0x%.4x, IRQ: %d\n",
  176.                device, serinfo.line, serial_type(serinfo.type),
  177.                serinfo.port, serinfo.irq);
  178.         printf("\tBaud_base: %d, close_delay: %d, divisor: %d\n",
  179.                serinfo.baud_base, serinfo.close_delay,
  180.                serinfo.custom_divisor);
  181.         print_flags(&serinfo, "\tFlags: ", "");
  182.         printf("\n\n");
  183.     } else if (verbosity==0) {
  184.         if (serinfo.type) {
  185.             printf("%s at 0x%.4x (irq = %d) is a %s",
  186.                    device, serinfo.port, serinfo.irq,
  187.                    serial_type(serinfo.type));
  188.             print_flags(&serinfo, " (", ")");
  189.             printf("\n");
  190.         }
  191.     } else {
  192.         printf("%s, UART: %s, Port: 0x%.4x, IRQ: %d",
  193.                device, serial_type(serinfo.type),
  194.                serinfo.port, serinfo.irq);
  195.         print_flags(&serinfo, ", Flags: ", "");
  196.         printf("\n");
  197.     }
  198.     close(fd);
  199. }
  200.  
  201. void set_serial(char *device, char ** arg)
  202. {
  203.     struct serial_struct old_serinfo, new_serinfo;
  204.     struct    flag_type_table    *p;
  205.     int    fd;
  206.     int    do_invert = 0;
  207.     char    *word;
  208.     
  209.  
  210.     if ((fd = open(device, O_RDWR|O_NONBLOCK)) < 0) {
  211.         if (verbosity==0 && errno==ENOENT)
  212.             exit(201);
  213.         perror(device);
  214.         exit(201);
  215.     }
  216.     if (ioctl(fd, TIOCGSERIAL, &old_serinfo) < 0) {
  217.         perror("Cannot get serial info");
  218.         exit(1);
  219.     }
  220.     new_serinfo = old_serinfo;
  221.     while (*arg) {
  222.         do_invert = 0;
  223.         word = *arg++;
  224.         if (*word == '^') {
  225.             do_invert++;
  226.             word++;
  227.         }
  228.         for (p = flag_type_tbl; p->name; p++) {
  229.             if (!strcasecmp(p->name, word))
  230.                 break;
  231.         }
  232.         if (!p->name) {
  233.             fprintf(stderr, "Invalid flag: %s\n", word);
  234.             exit(1);
  235.         }
  236.         if (do_invert && !(p->flags & FLAG_CAN_INVERT)) {
  237.             fprintf(stderr, "This flag can not be inverted: %s\n", word);
  238.             exit(1);
  239.         }
  240.         if ((p->flags & FLAG_NEED_ARG) && !*arg) {
  241.             fprintf(stderr, "Missing argument for %s\n", word);
  242.             exit(1);
  243.         }
  244.         switch (p->cmd) {
  245.         case CMD_FLAG:
  246.             new_serinfo.flags &= ~p->mask;
  247.             if (!do_invert)
  248.                 new_serinfo.flags |= p->bits;
  249.             break;
  250.         case CMD_PORT:
  251.             new_serinfo.port = atonum(*arg++);
  252.             break;
  253.         case CMD_IRQ:
  254.             new_serinfo.irq = atonum(*arg++);
  255.             break;
  256.         case CMD_DIVISOR:
  257.             new_serinfo.custom_divisor = atonum(*arg++);
  258.             break;
  259.         case CMD_TYPE:
  260.             new_serinfo.type = uart_type(*arg++);
  261.             if (new_serinfo.type < 0) {
  262.                 fprintf(stderr, "Illegal UART type: %s", *--arg);
  263.                 exit(1);
  264.             }
  265.             break;
  266.         case CMD_BASE:
  267.             new_serinfo.baud_base = atonum(*arg++);
  268.             break;
  269.         case CMD_DELAY:
  270.             new_serinfo.close_delay = atonum(*arg++);
  271.             break;
  272.         case CMD_CONFIG:
  273.             if (ioctl(fd, TIOCSSERIAL, &new_serinfo) < 0) {
  274.                 perror("Cannot set serial info");
  275.                 exit(1);
  276.             }
  277.             if (ioctl(fd, TIOCSERCONFIG) < 0) {
  278.                 perror("Cannot autoconfigure port");
  279.                 exit(1);
  280.             }
  281.             if (ioctl(fd, TIOCGSERIAL, &new_serinfo) < 0) {
  282.                 perror("Cannot get serial info");
  283.                 exit(1);
  284.             }
  285.             break;
  286.         default:
  287.             fprintf(stderr, "Internal error: unhandled cmd #%d\n", p->cmd);
  288.             exit(1);
  289.         }
  290.     }
  291.     if (ioctl(fd, TIOCSSERIAL, &new_serinfo) < 0) {
  292.         perror("Cannot set serial info");
  293.         exit(1);
  294.     }
  295.     close(fd);
  296.     if (verbose_flag)
  297.         get_serial(device);
  298. }
  299.  
  300. void do_wild_intr(char *device)
  301. {
  302.     int    fd;
  303.     int    i, mask;
  304.     int    wild_mask = -1;
  305.     
  306.     if ((fd = open(device, O_RDWR|O_NONBLOCK)) < 0) {
  307.         perror(device);
  308.         exit(1);
  309.     }
  310.     if (ioctl(fd, TIOCSERSWILD, &wild_mask) < 0) {
  311.         perror("Cannot scan for wild interrupts");
  312.         exit(1);
  313.     }
  314.     if (ioctl(fd, TIOCSERGWILD, &wild_mask) < 0) {
  315.         perror("Cannot get wild interrupt mask");
  316.         exit(1);
  317.     }
  318.     close(fd);
  319.     if (quiet_flag)
  320.         return;
  321.     if (wild_mask) {
  322.         printf("Wild interrupts found: ");
  323.         for (i=0, mask=1; mask <= wild_mask; i++, mask <<= 1)
  324.             if (mask & wild_mask)
  325.                 printf(" %d", i);
  326.         printf("\n");
  327.     } else if (verbose_flag)
  328.         printf("No wild interrupts found.\n");
  329.     return;
  330. }
  331.  
  332.  
  333.  
  334.  
  335. void usage()
  336. {
  337.     fprintf(stderr, "setserial Version %s\n\n", VERSION_STR);
  338.     fprintf(stderr,
  339.         "usage: %s serial-device [cmd1 [arg]] ... \n\n", progname);
  340.     fprintf(stderr, "Available commands: (* = Takes an argument)\n");
  341.     fprintf(stderr, "\t\t(^ = can be preceded by a '^' to turn off the option)\n");
  342. fprintf(stderr, "\t* port\t\tset the I/O port\n");
  343.     fprintf(stderr, "\t* irq\t\tset the interrupt\n");    
  344.     fprintf(stderr, "\t* uart\t\tset UART type (none, 8250, 16450, 16550, 16550A\n");
  345.     fprintf(stderr, "\t* baud_base\tset base baud rate (CLOCK_FREQ / 16)\n");
  346.     fprintf(stderr, "\t* divisor\tset the custom divisor (see spd_custom)\n");
  347.     fprintf(stderr, "\t* close_delay\tset the amount of time (in 1/100 of a\n");
  348.     fprintf(stderr, "\t\t\t\tsecond) that DTR should be kept low\n");
  349.     fprintf(stderr, "\t\t\t\twhile being closed\n");
  350.     
  351.     fprintf(stderr, "\t^ fourport\tconfigure the port as an AST Fourport\n");
  352.     fprintf(stderr, "\t  autoconfigure\tautomatically configure the serial port\n");
  353.     fprintf(stderr, "\t^ auto_irq\ttry to determine irq during autoconfiguration\n");
  354.     fprintf(stderr, "\t^ skip_test\tskip UART test during autoconfiguration\n");
  355.     fprintf(stderr, "\n");
  356.     fprintf(stderr, "\t^ sak\t\tset the break key as the Secure Attention Key\n");
  357.     fprintf(stderr, "\t^ session_lockout Lock out callout port across different sessions\n");
  358.     fprintf(stderr, "\t^ pgrp_lockout\tLock out callout port across different process groups\n");
  359. #ifdef ASYNC_CALLOUT_NOHUP
  360.     fprintf(stderr, "\t^ callout_nohup\tDon't hangup the tty when carrier detect drops\n");
  361. #endif
  362.     fprintf(stderr, "\t\t\t\t on the callout device\n");
  363. #ifdef ASYNC_SPLIT_TERMIOS
  364.     fprintf(stderr, "\t^ split_termios Use separate termios for callout and dailin lines\n");
  365. #endif    
  366.     fprintf(stderr, "\t^ hup_notify\tNotify a process blocked on opening a dial in line\n");
  367.     fprintf(stderr, "\t\t\t\twhen a process has finished using a callout\n");
  368.     fprintf(stderr, "\t\t\t\tline by returning EAGAIN to the open.\n");
  369.     fprintf(stderr, "\n");
  370.     fprintf(stderr, "\t  spd_hi\tuse 56kb instead of 38.4kb\n");
  371.     fprintf(stderr, "\t  spd_vhi\tuse 115kb instead of 38.4kb\n");
  372.     fprintf(stderr, "\t  spd_cust\tuse the custom divisor to set the speed at 38.4kb\n");
  373.     fprintf(stderr, "\t\t\t\t(baud rate = baud_base / custom_divisor)\n");
  374.     fprintf(stderr, "\t  spd_normal\tuse 38.4kb when a buad rate of 38.4kb is selected\n");
  375.     fprintf(stderr, "\n");
  376.     fprintf(stderr, "Use a leading '0x' for hex numbers.\n");
  377.     fprintf(stderr, "CAUTION: Using an invalid port can lock up your machine!\n");
  378.     exit(1);
  379. }
  380.  
  381. main(int argc, char **argv)
  382. {
  383.     int    get_flag = 0, wild_intr_flag = 0;
  384.     int    c;
  385.     extern int optind;
  386.     extern char *optarg;
  387.     
  388.     progname = argv[0];
  389.     if (argc == 1)
  390.         usage();
  391.     while ((c = getopt(argc, argv, "abgqvVW")) != EOF) {
  392.         switch (c) {
  393.         case 'a':
  394.             verbosity = 2;
  395.             break;
  396.         case 'b':
  397.             verbosity = 0;
  398.             break;
  399.         case 'q':
  400.             quiet_flag++;
  401.             break;
  402.         case 'v':
  403.             verbose_flag++;
  404.             break;
  405.         case 'g':
  406.             get_flag++;
  407.             break;
  408.         case 'V':
  409.             fprintf(stderr, "setserial version %s\n", VERSION_STR);
  410.             exit(0);
  411.         case 'W':
  412.             wild_intr_flag++;
  413.             break;
  414.         default:
  415.             usage();
  416.         }
  417.     }
  418.     if (get_flag) {
  419.         argv += optind;
  420.         while (*argv)
  421.             get_serial(*argv++);
  422.         exit(0);
  423.     }
  424.     if (argc == optind)
  425.         usage();
  426.     if (wild_intr_flag) {
  427.         do_wild_intr(argv[optind]);
  428.         exit(0);
  429.     }
  430.     if (argc-optind == 1)
  431.         get_serial(argv[optind]);
  432.     else
  433.         set_serial(argv[optind], argv+optind+1);
  434.     exit(0);
  435. }
  436.  
  437.